package com.example.android_media01

import android.app.Activity
import android.content.Intent
import android.media.MediaPlayer
import android.media.MediaPlayer.*
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Looper
import android.util.Log
import android.view.Gravity
import android.view.SurfaceView
import android.view.Window
import android.widget.FrameLayout
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_main.*
import java.io.FileDescriptor

class MainActivity : AppCompatActivity(), OnPreparedListener, OnErrorListener, OnCompletionListener, OnBufferingUpdateListener{

    companion object {
        const val TAG = "MainActivity"
    }

    private var mediaPlayer: MediaPlayer? = null
    private var mUIStatus: PlayerUIStatus = PlayerUIStatus.STOP
    private var mediaFileDesc: FileDescriptor? = null
    private lateinit var mDisplayView: SurfaceView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE)
        setContentView(R.layout.activity_main)
        btn_init.setOnClickListener {
            val url = edt_src.text.toString().trim()
            if (mediaFileDesc != null){
                initPlayer(mediaFileDesc)
            }else if (url.isNotEmpty()){
                initPlayer(url)
            }
        }
        btn_play.setOnClickListener {
            if (mUIStatus != PlayerUIStatus.PLAYING){
                play()
            } else if (mUIStatus == PlayerUIStatus.PLAYING){
                mediaPlayer?.run {
                    setUIStatus(PlayerUIStatus.PAUSE)
                    pause()
                }
            }
        }
        btn_stop.setOnClickListener {
            stop()
        }

        btn_select.setOnClickListener {
            selectFile()
        }
        setUIStatus(PlayerUIStatus.STOP)
    }

    private fun stop() {
        mediaPlayer?.run {
            setUIStatus(PlayerUIStatus.STOP)
            stop()
        }
        mediaFileDesc = null
    }

    private fun selectFile(){
        val intent = Intent(Intent.ACTION_GET_CONTENT)
        intent.setType("video/*")
        startActivityForResult(intent, 0)
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        if (requestCode == 0){
            if (resultCode == Activity.RESULT_OK){
                val uri = data?.data
                if (uri != null){
                    mediaFileDesc = contentResolver.openFileDescriptor(uri, "r")?.fileDescriptor
                    edt_src.setText(uri.toString())
                }
            }
        }
        super.onActivityResult(requestCode, resultCode, data)
    }

    private fun initPlayer(fd: FileDescriptor?){
        if (mediaPlayer == null){
            mediaPlayer = MediaPlayer()
        } else {
            mediaPlayer?.reset()
        }
        mediaPlayer?.setOnErrorListener(this)
        mediaPlayer?.setOnBufferingUpdateListener(this)
        if (fd != null){
            mediaPlayer?.run {
                setDataSource(fd)
                setOnPreparedListener(this@MainActivity)
                setUIStatus(PlayerUIStatus.LOADING)
                prepareAsync()
            }
        }
    }

    private fun initPlayer(url: String? = null){
        if (mediaPlayer == null){
            mediaPlayer = MediaPlayer()
        } else {
            mediaPlayer?.reset()
        }
        mediaPlayer?.setOnErrorListener(this)
        if (url != null){
            mediaPlayer?.run {
                setDataSource(url)
                setOnPreparedListener(this@MainActivity)
                setUIStatus(PlayerUIStatus.LOADING)
                prepareAsync()
            }
        }
    }

    override fun onPrepared(mp: MediaPlayer) {
        setUIStatus(PlayerUIStatus.READY)
        createDisplayView(mp.videoWidth, mp.videoHeight)
    }

    private fun createDisplayView(videoWidth: Int, videoHeight: Int){
        val fitW : Int
        val fitH : Int
        mDisplayView = SurfaceView(this)
        val wrapWidth = display_warp.width
        val wrapHeight = display_warp.height
        val wscale = wrapWidth * 1f / videoWidth
        val hscale = wrapHeight * 1f / videoHeight
        if (wscale < hscale){
            fitW = (videoWidth * wscale).toInt()
            fitH = (videoHeight * wscale).toInt()
        } else {
            fitW = (videoWidth * hscale).toInt()
            fitH = (videoHeight * hscale).toInt()
        }
        mDisplayView.layoutParams = FrameLayout.LayoutParams(fitW, fitH, Gravity.CENTER)
        display_warp.removeAllViews()
        display_warp.addView(mDisplayView)
    }

    private fun play(){
        if (mUIStatus == PlayerUIStatus.READY || mUIStatus == PlayerUIStatus.PAUSE){
            mediaPlayer?.run {
                setUIStatus(PlayerUIStatus.PLAYING)
                setDisplay(mDisplayView.holder)
                start()
            }
        }
    }

    private fun setUIStatus(status: PlayerUIStatus){
        mUIStatus = status
        notifyPlayerUI()
    }

    private fun notifyPlayerUI(){
        if (Thread.currentThread() == Looper.getMainLooper().thread){
             when(mUIStatus){
                PlayerUIStatus.STOP -> {
                    status.text = "STOP"
                    btn_play.text = "PLAY"
                }
                PlayerUIStatus.LOADING-> {
                    status.text = "LOADING"
                }
                PlayerUIStatus.READY -> {
                    status.text = "READY"
                }
                PlayerUIStatus.PLAYING -> {
                    status.text = "PLAYING"
                    btn_play.text = "PAUSE"
                }
                PlayerUIStatus.PAUSE -> {
                    status.text = "PAUSE"
                    btn_play.text = "PLAY"
                }
            }
        } else {
            runOnUiThread{
                  notifyPlayerUI()
            }
        }
    }

    override fun onError(mp: MediaPlayer, what: Int, extra: Int): Boolean {
        setUIStatus(PlayerUIStatus.STOP)
        val error = when(what){
            MEDIA_ERROR_IO -> "加载失败"
            MEDIA_ERROR_MALFORMED -> "非标准流"
            MEDIA_ERROR_UNSUPPORTED -> "不支持该视频"
            MEDIA_ERROR_TIMED_OUT -> "播放超时"
            else -> "未知错误"
        }
        Log.e(TAG, "onError: $what, $error")
        showToast(error)
        return true
    }

    private fun showToast(message: String){
        Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
    }

    override fun onCompletion(mp: MediaPlayer?) {
        setUIStatus(PlayerUIStatus.STOP)
    }

    override fun onBufferingUpdate(mp: MediaPlayer?, percent: Int) {
        Log.d(TAG, "onBufferingUpdate: $percent")
        buffer.setText(String.format(getString(R.string.buffer), percent.toString()))
    }
}

enum class PlayerUIStatus{
    STOP, LOADING, READY, PLAYING, PAUSE
}
